/**
 * 业务代码版本, 包含一个提交对象
 */
package indi.zjh.dp.vc;

import indi.zjh.dp.db.Configuration;
import indi.zjh.dp.db.DataSource;
import indi.zjh.dp.db.Session;
import indi.zjh.dp.db.Table;
import indi.zjh.dp.db.TableRepository;
import indi.zjh.dp.dynamic.DynamicEngine;
import indi.zjh.dp.error.UnsuportedFieldException;
import indi.zjh.dp.orm.Business;
import indi.zjh.dp.orm.BusinessListener;
import indi.zjh.dp.orm.BusinessMapDataStrategy;
import indi.zjh.dp.orm.BusinessStructEvent;
import indi.zjh.dp.orm.BusinessStructListener;
import indi.zjh.dp.orm.MethodFactory;
import indi.zjh.dp.orm.Relation;
import indi.zjh.dp.orm.RelationClass;
import indi.zjh.dp.startup.Application;
import indi.zjh.dp.startup.Constant;
import indi.zjh.dp.util.ClassUtil;
import indi.zjh.dp.util.FileUtil;
import indi.zjh.dp.util.RedisUtil;
import indi.zjh.dp.util.XMLUtil;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dom4j.DocumentException;

import com.mysql.jdbc.MysqlDataTruncation;


public class Version 
{
	private static Logger logger = Logger.getLogger(Version.class);
	
	// 该版本包含的提交对象
	protected Commit commit = null;
	// 该版本包含的所有业务类, 类名 -> 类对象
	protected Map<String, FileObject> allFileObject; 
	// 类名 -> 类模版
	protected Map<String, Class<?>> allClass;
	// 版本检出的存放路径
	protected String checkoutDirectory;
	// 类名 -> 业务类
	protected Map<String, RelationClass> allRelationClass;
	
	protected long createTimestamp = 0;
	
	// 监听业务模型关系事件的监听器
	protected List<BusinessStructListener> listener;
	
	/**
	 * 从别的目录检出的版本
	 * @param cmt
	 * @param dir
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws IOException
	 * @throws UnsuportedFieldException 
	 * @throws ClassNotFoundException 
	 */
	public Version(Commit cmt, String dir) throws IllegalAccessException, InstantiationException, IOException, UnsuportedFieldException, ClassNotFoundException
	{
		this.commit = cmt;
		this.allFileObject = new HashMap<String, FileObject>();
		this.allClass = new HashMap<String, Class<?>>();
		this.allRelationClass = new HashMap<String, RelationClass>();
		this.listener = new ArrayList<BusinessStructListener>();
		this.checkoutDirectory = dir;
		Map<String, FileObject> fileObject = cmt.getFileObjectMap();
		Iterator<Map.Entry<String, FileObject>> iter = fileObject.entrySet().iterator();
		while(iter.hasNext())
		{
			FileObject fo = iter.next().getValue();
			this.allFileObject.put(fo.getClassName(), fo);
			String filePath = this.checkoutDirectory + File.separator + fo.getClassName().replace(".", File.separator) + ".java";
			Class<?> cls = DynamicEngine.getInstance().javaCodeToClass(fo.getClassName(), FileUtil.getFileContent(filePath));
			this.allClass.put(fo.getClassName(), cls);
			RelationClass rc = new RelationClass(cls);
			if(rc.isBusiness())
			{
				this.allRelationClass.put(rc.getName(), rc);
			}
		}
		
		
	}
	
	/**
	 * 获取当前源代码的业务版本
	 * @throws Exception 
	 */
	public Version() throws Exception
	{
		this.createTimestamp = new Date().getTime();
		// 非检出版本, 没有提交信息
		MethodFactory.init();
		this.commit = null;
		this.allFileObject = null;
		this.checkoutDirectory = null;
		
		// 初始化
		this.allClass = new HashMap<String, Class<?>>();
		this.allRelationClass = new HashMap<String, RelationClass>();
		this.listener = new ArrayList<BusinessStructListener>();
		
		////////////////////////////////////////////////////////
		// 获取配置的业务包列表
		String[] packageList = XMLUtil.getStringList(Constant.CONF_FILE, "/Business/package-list/package");
		if(packageList.length == 0)
		{
			throw new Exception("There is no business package");
		}
		
		List<Class<?>> classes = ClassUtil.getClassesByPackages(packageList);
		for(int i = 0; i < classes.size(); ++i)
		{
			RelationClass rClass = new RelationClass(classes.get(i));
			if(!rClass.isBusiness())
				continue;
			
			this.allClass.put(classes.get(i).getName(), classes.get(i));
			this.registerBusinessStructListener(rClass);
			this.allRelationClass.put(rClass.getName(), rClass);
			if(rClass.isBusiness())
			{
				this.allRelationClass.put(classes.get(i).getName(), rClass);
			}
			
		}
		////////////////////////////////////////////////////////
		
		
	
	}
	
	/**
	 * 通过类名查找业务类, 并且返回, 找不到创建
	 * @param className: 类名
	 * @return: 业务类, 如果不是业务类就返回null
	 * @throws UnsuportedFieldException 
	 * @throws ClassNotFoundException 
	 */
	public RelationClass getRelationClass(String className) throws UnsuportedFieldException, ClassNotFoundException
	{
		if(!this.allClass.containsKey(className))
		{
			throw new ClassNotFoundException(className);
		}
		if(!this.allRelationClass.containsKey(className))
		{
			Class<?> cls = this.allClass.get(className);
			RelationClass rc = new RelationClass(cls);
			
			this.allRelationClass.put(className, rc);
		}
		return this.allRelationClass.get(className);
	}
	
	private void analyzeInheritRelationClass() throws UnsuportedFieldException, ClassNotFoundException
	{
		// 扫描继承关系树
		Iterator<Map.Entry<String, Class<?>>> iter1 = this.allClass.entrySet().iterator();
		while(iter1.hasNext())
		{
			Map.Entry<String, Class<?>> entry = iter1.next();
			String className = entry.getKey();

			Class<?> clazz = entry.getValue();
			// 处理继承关系
			Class<?> c = clazz;
			do
			{
				Class<?> parent = c.getSuperclass();
				if(parent.getName().equals(Constant.BUSINESS_BASE_CLASS_NAME))
					break;

				// 连接父类关系
				this.getRelationClass(c.getName()).parentClass = this.getRelationClass(parent.getName());
				// 连接子类关系
				if(this.getRelationClass(parent.getName()).subClass == null)
					this.getRelationClass(parent.getName()).subClass = new HashSet<RelationClass>();
				this.getRelationClass(parent.getName()).subClass.add(this.getRelationClass(c.getName()));
				c = parent;
			}while(true);
		}
	}
	
	private void analyzeAggregationRelationClass(RelationClass rc) throws UnsuportedFieldException, ClassNotFoundException
	{

		Iterator<Map.Entry<String, String>> niter = rc.aggregationFieldMap.entrySet().iterator();
		while(niter.hasNext())
		{
			Map.Entry<String, String> nentry = niter.next();
			RelationClass aggreClass = this.getRelationClass(nentry.getValue());
			if(aggreClass != null)
				aggreClass.aggregationedClass.add(rc);
		}
		
	}
	
	private void analyzeAssociationRelationClass(RelationClass rc) throws InstantiationException, IllegalAccessException, UnsuportedFieldException, ClassNotFoundException
	{
		if(rc.associationFieldSet.size() > 0)
		{
			Business obj = (Business)rc.getClazz().newInstance();
			Iterator<Field> iter = rc.associationFieldSet.iterator();
			while(iter.hasNext())
			{
				Field f = iter.next();
				f.setAccessible(true);
				Relation rel = (Relation)f.get(obj);
				RelationClass orc = this.getRelationClass(rel.getRelationClassName());
				rc.associationClass.add(orc);
				orc.associationClass.add(rc);
			}
		}
	}
	
	private Set<RelationClass> analyzeContainRelationClass(RelationClass rc) throws UnsuportedFieldException, ClassNotFoundException
	{
		List<Field> fields = rc.getFields();
		Iterator<Field> iter = fields.iterator();
		Set<RelationClass> gloret = new HashSet<RelationClass>();
		while(iter.hasNext())
		{
			Field f = iter.next();
			f.setAccessible(true);
			Set<RelationClass> thisret = null;
			if(Business.class.isAssignableFrom(f.getType()))
			{
				if(rc.containingField == null)
					rc.containingField = new HashMap<String, Field>();
				rc.containingField.put(f.getName(), f);

				rc.directContainingClass.add(this.getRelationClass(f.getType().getName()));
				RelationClass rced = this.getRelationClass(f.getType().getName());
				gloret.add(rced);
				
				if(rced.containedClass == null)
					rced.containedClass = new HashSet<RelationClass>();
				rced.containedClass.add(rc);
				thisret = this.analyzeContainRelationClass(rced);
				gloret.addAll(thisret);
				
				Iterator<RelationClass> tmpiter = thisret.iterator();
				while(tmpiter.hasNext())
				{
					RelationClass rcedd = tmpiter.next();
					if(rcedd.containedClass == null)
						rcedd.containedClass = new HashSet<RelationClass>();
					rcedd.containedClass.add(rc);
				}
			}
		}
		
		return gloret;
	}
	
	private void processInheritRelationClass() throws Exception
	{
		Iterator<Map.Entry<String, RelationClass>> iter = this.allRelationClass.entrySet().iterator();
		while(iter.hasNext())
		{
			Map.Entry<String, RelationClass> entry = iter.next();
			RelationClass rClass = entry.getValue();
			// 找到顶级业务父类
			if(rClass.parentClass == null)
			{
				BusinessStructEvent event = new BusinessStructEvent();
				event.setType(BusinessStructEvent.FATHER_TO_SON);
				event.setSubject(rClass);
				event.setObject(null);
				this.fireBusinessStructEvent(event);
			}
		}

	}
	
	private void processInitRelationClass() throws Exception
	{
		BusinessStructEvent event = new BusinessStructEvent();
		event.setSubject(null);
		event.setObject(null);
		event.setType(BusinessStructEvent.INIT);
		this.fireBusinessStructEvent(event);
	}
	
	private void processDirectSubClass()
	{
		Iterator<Map.Entry<String, RelationClass>> iter3 = this.allRelationClass.entrySet().iterator();
		while(iter3.hasNext())
		{
			RelationClass rc = iter3.next().getValue();
			if(rc.subClass == null || rc.subClass.size() == 0)
				continue;

			Iterator<RelationClass> siter = rc.subClass.iterator();
			while(siter.hasNext())
			{
				RelationClass subrc = siter.next();
				if(subrc.parentClass.getName().equals(rc.getName()))
				{
					rc.directSubClass.add(subrc);
				}
			}

		}
	}
	
	private void processContainRelationClass() throws Exception
	{
		Iterator<Map.Entry<String, RelationClass>> iter = this.allRelationClass.entrySet().iterator();
		while(iter.hasNext())
		{
			RelationClass rc = iter.next().getValue();
			if(rc.containingClass != null && rc.containingClass.size() > 0)
			{
				Iterator<RelationClass> niter = rc.containingClass.iterator();
				while(niter.hasNext())
				{
					RelationClass rced = niter.next();
					
					BusinessStructEvent event = new BusinessStructEvent();
					event.setSubject(rc);
					event.setObject(rced);
					event.setType(BusinessStructEvent.CONTAINING);
					this.fireBusinessStructEvent(event);
				}
			}
			
		}
	}
	
	/**
	 * 分析该版本的业务类之间的关系
	 * @throws Exception 
	 */
	public void analyzeClassRelation() throws Exception
	{
		this.analyzeInheritRelationClass();
		
		
		// 扫描组合关系树
		Iterator<Map.Entry<String, Class<?>>> iter1 = this.allClass.entrySet().iterator();
		while(iter1.hasNext())
		{
			Map.Entry<String, Class<?>> entry = iter1.next();
			String className = entry.getKey();
			Class<?> clazz = entry.getValue();
			
			RelationClass rc = this.getRelationClass(className);
			analyzeAggregationRelationClass(rc);
			rc.containingClass = this.analyzeContainRelationClass(rc);
			this.analyzeAssociationRelationClass(rc);
		}
		
		this.processInheritRelationClass();
		
		this.processContainRelationClass();
		
		this.processDirectSubClass();
		
		// 必须放在解析的最后
		this.processInitRelationClass();
		
		logger.debug("当前版本的业务类个数:"+this.allRelationClass.size());
		Iterator<Map.Entry<String, RelationClass>> iter3 = this.allRelationClass.entrySet().iterator();
		while(iter3.hasNext())
		{
			RelationClass rc = iter3.next().getValue();
			// 找到继承树祖先
//			System.out.println("遍历"+rc.getName());
//			System.out.println(rc.getDirectSubClassSetInfo());
//			System.out.println(rc.getParentClassListInfo());
//			System.out.println(rc.getSubClassSetInfo());
//			System.out.println(rc.getContainingClassSetInfo());
//			System.out.println(rc.getDirectContainingClassSetInfo());
//			System.out.println(rc.getAssociationClassSetInfo());
//			System.out.println(rc.getContainedClassSetInfo());
//			System.out.println(rc.getContainingFieldSetInfo());
		}
		
//		// 触发模型关系事件
//		System.out.println("当前版本的业务类个数:"+this.allRelationClass.size());
//		Iterator<Map.Entry<String, RelationClass>> iter2 = this.allRelationClass.entrySet().iterator();
//		while(iter2.hasNext())
//		{
//			RelationClass rc = iter2.next().getValue();
//			// 找到继承树祖先
//			//System.out.println("遍历"+rc.getName());
//			System.out.println(rc.getSubClassSetInfo());
//			System.out.println(rc.getContainingClassSetInfo());
//			System.out.println(rc.getContainedClassSetInfo());
//			
//			// 触发继承关系事件
//			if(rc.parentClass == null)
//			{
//				BusinessStructEvent event = new BusinessStructEvent();
//				event.setType(BusinessStructEvent.FATHER_TO_SON);
//				event.setSubject(rc);
//				event.setObject(null);
//				this.fireBusinessStructEvent(event);
//			}
//			
//			// 触发继承关系事件
//			if(rc.subClass == null)
//			{
//				BusinessStructEvent event = new BusinessStructEvent();
//				event.setType(BusinessStructEvent.SON_TO_FATHER);
//				event.setSubject(null);
//				event.setObject(rc);
//				this.fireBusinessStructEvent(event);
//			}
//
//
//			// 触发组合关系事件
//			if(rc.containingClass != null && rc.containingClass.size() > 0)
//			{
//				Iterator<RelationClass> niter = rc.containingClass.iterator();
//				while(niter.hasNext())
//				{
//					BusinessStructEvent event = new BusinessStructEvent();
//					event.setType(BusinessStructEvent.CONTAINING);
//					event.setSubject(rc);
//					event.setObject(niter.next());
//					this.fireBusinessStructEvent(event);
//				}
//			}
//			
//			
//		}
	}
	
	/**
	 * 初始化数据库
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws Exception
	 */
	public void initial() throws SQLException, DocumentException, Exception
	{
		this.processInitRelationClass();
		
		Iterator<Map.Entry<String, RelationClass>> iter = this.allRelationClass.entrySet().iterator();
		Session cSession = Configuration.getSessionFactory().createSession();
		DataSource.init(cSession);
		while(iter.hasNext())
		{
			Map.Entry<String, RelationClass> entry = iter.next();
			RelationClass rClass = entry.getValue();
			
			//Business obj = (Business)rClass.getClazz().newInstance();
			//String sql = BusinessMapDataStrategy.getCreateSql(obj);
			String sql = TableRepository.getInstance().getCreateSql(rClass.getClazz().getName());
			System.out.println(sql);
			cSession.alter(sql);
		}
		
		cSession.close();
	}
	
	public void run() throws SQLException, DocumentException, Exception
	{
//		RedisUtil.init();
//		BusinessStart.run();
//		RedisUtil.finish();
	}
	
	/**
	 * 清空数据库
	 * @throws SQLException
	 * @throws DocumentException
	 * @throws Exception
	 */
	public void clear() throws SQLException, DocumentException, Exception
	{
		Session session = Configuration.getSessionFactory().createSession();
		session.loadTables();
		String[] tables = session.getAllTable();
		for(String tableName:tables)
		{
			// 不删除数据源表
			if(tableName.equals(DataSource.getTableName()))
				continue;
			Table table = new Table(tableName);
			String sql = table.getDropSql();
			session.alter(sql);
		}
		
		// 删除dsrc表
		Table dsrct = new Table("dsrc");
		session.alter(dsrct.getDropSql());
		
		session.close();
	}
	
	public void clearData() throws SQLException, DocumentException, Exception
	{
		Session session = Configuration.getSessionFactory().createSession();
		session.loadTables();
		String[] tables = session.getAllTable();
		for(String tableName:tables)
		{
			Table table = new Table(tableName);
			String sql = table.getClearSql();
			session.execute(sql);
			session.commit();
		}
		
		session.close();
	}
	
	/**
	 * 注册业务模型关系事件监听器
	 * @param lner
	 */
	public void registerBusinessStructListener(BusinessStructListener lner)
	{
		this.listener.add(lner);
	}
	
	/**
	 * 触发业务模型关系事件
	 * @param event
	 * @throws Exception 
	 */
	public void fireBusinessStructEvent(BusinessStructEvent event) throws Exception
	{
		Iterator<BusinessStructListener> iter = this.listener.iterator();
		int type = event.getType();
		while(iter.hasNext())
		{
			BusinessStructListener lner = iter.next();
			
			switch (type) 
			{
			case BusinessStructEvent.INIT:
				lner.init(event);
				break;
			case BusinessStructEvent.FATHER_TO_SON:
			case BusinessStructEvent.SON_TO_FATHER:
				lner.extend(event);
				break;
			case BusinessStructEvent.CONTAINING:
				lner.composition(event);
				break;
			default:
				break;
			}
		}
	}
	
	public String toString()
	{
		StringBuilder sb = new StringBuilder();
		if(this.commit == null)
		{
			sb.append("版本:当前版本\n");
		}
		else
		{
			sb.append("版本:"+this.commit.getDesc()+"\n");
		}
		sb.append("业务类:\n");
		Iterator<Map.Entry<String, Class<?>>> iter = this.allClass.entrySet().iterator();
		while(iter.hasNext())
		{
			Class<?> cls = iter.next().getValue();
			sb.append("\t" + cls.getName() + "\n");
			//RelationClass rc = new RelationClass(cls);
			//sb.append(rc);
		}
		return sb.toString();
	}
	
	/**
	 * 获取业务类的迭代器
	 * @return 迭代器
	 */
	public Iterator<Map.Entry<String, RelationClass>> getRelationClassIterator()
	{
		return this.allRelationClass.entrySet().iterator();
	}
	
	/**
	 * 获取业务类的个数
	 * @return
	 */
	public int getRelationClassCount()
	{
		return this.allRelationClass.size();
	}
	
	/**
	 * 生成类关系图
	 */
	public int createRelationChart()
	{
		System.out.println(this.allRelationClass);
		return 0;
	}
	
	public long getTimestamp()
	{
		if(this.commit == null)
			return this.createTimestamp;
		return this.commit.getTimestamp();
	}

}
